<?php
declare(strict_types=1);

namespace app\common\library;

use app\common\model\delivery\PayLog;
use app\common\model\Third;
use Yansongda\Pay\Pay as YansongdaPay;

class Pay
{
    private $config;

    public function __construct(string $sub_mch_id)
    {
        $this->config=[
            'wechat' => [
                'default' => [
                    // 必填-商户号，服务商模式下为服务商商户号
                    // 可在 https://pay.weixin.qq.com/ 账户中心->商户信息 查看
                    'mch_id' => '1673386330',
                    // 选填-v2商户私钥
                    'mch_secret_key_v2' => '',
                    // 必填-v3 商户秘钥
                    // 即 API v3 密钥(32字节，形如md5值)，可在 账户中心->API安全 中设置
                    'mch_secret_key' => 'kgCUIsUkmgboySTAixPlhyMDgCNYHqET',
                    // 必填-商户私钥 字符串或路径
                    // 即 API证书 PRIVATE KEY，可在 账户中心->API安全->申请API证书 里获得
                    // 文件名形如：apiclient_key.pem
                    'mch_secret_cert' => root_path().'cert/apiclient_key.pem',
                    // 必填-商户公钥证书路径
                    // 即 API证书 CERTIFICATE，可在 账户中心->API安全->申请API证书 里获得
                    // 文件名形如：apiclient_cert.pem
                    'mch_public_cert_path' => root_path().'cert/apiclient_cert.pem',
                    // 必填-微信回调url
                    // 不能有参数，如?号，空格等，否则会无法正确回调
                    'notify_url' =>request()->domain().'/api/mpwechat/notify/'.$sub_mch_id,
                    // 选填-公众号 的 app_id
                    // 可在 mp.weixin.qq.com 设置与开发->基本配置->开发者ID(AppID) 查看
                    'mp_app_id' => site_config("addons.uniapp_mpapp_id"),
                    // 选填-小程序 的 app_id
                    'mini_app_id' => site_config("addons.uniapp_miniapp_id"),
                    // 选填-app 的 app_id
                    'app_id' => '',
                    // 选填-合单 app_id
                    'combine_app_id' => '',
                    // 选填-合单商户号
                    'combine_mch_id' => '',
                    // 选填-服务商模式下，子公众号 的 app_id
                    'sub_mp_app_id' => '',
                    // 选填-服务商模式下，子 app 的 app_id
                    'sub_app_id' =>'',
                    // 选填-服务商模式下，子小程序 的 app_id
                    'sub_mini_app_id' => '',
                    // 选填-服务商模式下，子商户id
                    'sub_mch_id' => $sub_mch_id,
                    // 选填-微信平台公钥证书路径, optional，强烈建议 php-fpm 模式下配置此参数
                    'wechat_public_cert_path' => [
                        '45F59D4DABF31918AFCEC556D5D2C6E376675D57' => '',
                    ],
                    // 选填-默认为正常模式。可选为： MODE_NORMAL, MODE_SERVICE
                    'mode' => YansongdaPay::MODE_SERVICE,
                ]
            ],
            'logger' => [
                'enable' => false,
                'file' => root_path().'runtime'.DS.'pay.log',
                'level' => 'info', // 建议生产环境等级调整为 info，开发环境为 debug
                'type' => 'single', // optional, 可选 daily.
                'max_file' => 30, // optional, 当 type 为 daily 时有效，默认 30 天
            ],
            'http' => [ // optional
                'timeout' => 5.0,
                'connect_timeout' => 5.0,
            ],
        ];
        YansongdaPay::config($this->config);
    }

    /**
     * 统一下单API
     * @param $orderNo
     * @param $openid
     * @param $totalFee
     * @param $orderType 订单类型
     * @return array
     * @throws BaseException
     */
    public function unifiedorder(string $orderNo,int $user_id,float $totalFee,string $body,string $type,string $platform='mp')
    {
        $log=new PayLog();
        $log->save([
            'user_id'=>$user_id,
            'type'=>$type,
            'pay_price'=>$totalFee,
            'out_trade_no'=>$orderNo,
            'pay_status'=>0,
            'pay_time'=>date('Y-m-d H:i:s',time())
        ]);
        $order = [
            'out_trade_no' => $orderNo,
            'description' => $body,
            "attach"=>$type,
            'amount' => [
                'total' => $totalFee*100,
            ],
            'payer' => [
                'sp_openid' => '',
            ],
        ];
        if($platform=='miniapp'){
            $openid=Third::where(['user_id'=>$user_id,'platform'=>'miniapp'])->value('openid');
            $order['payer']['sp_openid']=$openid;
            return YansongdaPay::wechat()->mini($order);
        }
        if($platform=='mp'){
            $openid=Third::where(['user_id'=>$user_id,'platform'=>'wechat'])->value('openid');
            $order['payer']['sp_openid']=$openid;
            return YansongdaPay::wechat()->mp($order);
        }
    }

    /**
     * 申请退款API
     * @param $transaction_id
     * @param double $total_fee 订单总金额
     * @param double $refund_fee 退款金额
     * @return bool
     * @throws BaseException
     */
    public function refund(string $out_trade_no,float $total_fee,float $refund_fee)
    {
        $order = [
            'out_trade_no' => $out_trade_no,
            'out_refund_no' => create_out_trade_no(),
            'amount' => [
                'refund' => $refund_fee*100,
                'total' => $total_fee*100,
                'currency' => 'CNY',
            ],
        ];
        return YansongdaPay::wechat()->refund($order);
    }

    /**
     * 支付成功异步通知
     * @throws BaseException
     * @throws \Exception
     */
    public function notify()
    {
        $result = YansongdaPay::wechat()->callback();
        //$result =1;
        if($result){
            $data=$result->all();
            //file_put_contents('notify.txt',var_export($data,true));
            $attach=$data['resource']['ciphertext']['attach'];
            $out_trade_no=$data['resource']['ciphertext']['out_trade_no'];
            $amount=$data['resource']['ciphertext']['amount']['total'];
            $transaction_id=$data['resource']['ciphertext']['transaction_id'];
            /* @var PayLog $order*/
            $order=PayLog::where(['type'=>$attach,'out_trade_no'=>$out_trade_no])->find();
            if(!$order){
                $this->returnCode(false, '找不到订单');
            }
            if($order->pay_price*100!=$amount){
                $this->returnCode(false, '金额不对');
            }
            if($order->pay_status){
                $this->returnCode(true, 'OK');
            }
            if($order->paySuccess($transaction_id)){
                $this->returnCode(true, 'OK');
            }else{
                $this->returnCode(false, $order->getError());
            }
            $this->returnCode(true, 'OK');
        }
    }

    private function returnCode($returnCode = true, $msg = null)
    {
        // 返回状态
        $return = [
            'return_code' => $returnCode ? 'SUCCESS' : 'FAIL',
            'return_msg' => $msg ?: 'OK',
        ];
        die($this->toXml($return));
    }

    /**
     * 输出xml字符
     * @param $values
     * @return bool|string
     */
    private function toXml($values)
    {
        if (!is_array($values)
            || count($values) <= 0
        ) {
            return false;
        }

        $xml = "<xml>";
        foreach ($values as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

}
